#pragma once

#include <iostream>
#include <string>
#include <jsoncpp/json/json.h>

// #define MySelf 1

const std::string blank_space_sep = " ";
const std::string protocol_sep = "\n";

//把要发给业务处理的数据加工成报文
std::string Encode(std::string& content)
{
    //计算出数据的长度
    std::string len = std::to_string(content.size());

    //加工成新的字符串
    //len\ncontent\n
    std::string package = len;
    package += protocol_sep;
    package += content;
    package += protocol_sep;

    return package;
}

//传入报文数据流，获取第一个报文的正文
bool Decode(std::string& package, std::string* content)
{
    //package数据流
    //"len"\n"x op y"\n"len"\n"x op y"\n"len"\n"x... 报文都是连着的，需要自己识别提取一份报文

    //找到\n间隔符
    std::size_t pos = package.find(protocol_sep);
    if(pos == std::string::npos) return false;

    //找到正文长度
    std::string len_str = package.substr(0, pos);
    std::size_t len = std::stoi(len_str);
    //计算得出该报文应该有的长度，判断不能少于该长度
    std::size_t total_len = len_str.size() + len + 2;
    if(package.size() < total_len) return false;

    //获取正文
    *content = package.substr(pos+1, len);

    //获取正文后，在数据流中移除该报文
    package.erase(0, total_len);

    return true;
}

//管理描述要发给业务处理的数据
class Request
{
public:
    Request(int data1, int data2, char oper) 
    : x(data1)
    , y(data2)
    , op(oper)
    {}
    Request()
    {}

    //序列化
    //把数据构建成指定格式的字符串，然后传出去
    bool Serialize(std::string* out)
    {
#ifdef MySelf
        // 构建报文的有效载荷
        // struct => string, "x op y"
        std::string s = std::to_string(x);
        s += blank_space_sep;
        s += op;
        s += blank_space_sep;
        s += std::to_string(y);
        *out = s;

        return true;
#else
        Json::Value root;
        root["x"] = x;
        root["y"] = y;
        root["op"] = op;

        //将Value转化为字符串
        // Json::FastWriter w; //格式紧凑
        Json::StyledWriter w; //格式易读
        *out = w.write(root);

        return true;
#endif
    }
    //反序列化
    //解析正文，填充成员变量
    bool Deserialize(const std::string& in) 
    {
#ifdef MySelf
        // "x op y"
        //找到两个空格，判断位置是否合理
        std::size_t left = in.find(blank_space_sep);
        if (left == std::string::npos)
            return false;
        std::size_t right = in.rfind(blank_space_sep);
        if (right == std::string::npos)
            return false;
        if (left + 2 != right)
            return false;

        //通过空格找到数据
        std::string part_x = in.substr(0, left);
        std::string part_y = in.substr(right + 1);
        op = in[left + 1];
        x = std::stoi(part_x);
        y = std::stoi(part_y);
        
        return true;
#else
        //将字符串解析并存储到Value对象中
        Json::Value root;
        Json::Reader r;
        r.parse(in, root);

        //通过键值获取数据
        x = root["x"].asInt();
        y = root["y"].asInt();
        op = root["op"].asInt();

        return true;
#endif
    }

public:
    //本次业务是运算 x op y
    int x; //数字
    int y;
    char op; // + - * / % 运算符
};

//管理描述业务处理后的结果
class Response
{
public:
    Response(int res, int c) 
    : result(res)
    , code(c)
    {}
    Response()
    {}

    bool Serialize(std::string* out)
    {
#ifdef MySelf
        // "result code"
        // 构建报文的有效载荷
        std::string s = std::to_string(result);
        s += blank_space_sep;
        s += std::to_string(code);
        *out = s;

        return true;
#else
        Json::Value root;
        root["result"] = result;
        root["code"] = code;

        // Json::FastWriter w;
        Json::StyledWriter w;
        *out = w.write(root);

        return true;
#endif
    }
    bool Deserialize(const std::string& in) 
    {
#ifdef MySelf
        // "result code"
        std::size_t pos = in.find(blank_space_sep);
        if (pos == std::string::npos)
            return false;
        std::string part_left = in.substr(0, pos);
        std::string part_right = in.substr(pos+1);
        result = std::stoi(part_left);
        code = std::stoi(part_right);

        return true;
#else
        Json::Value root;
        Json::Reader r;
        r.parse(in, root);

        result = root["result"].asInt();
        code = root["code"].asInt();

        return true;
#endif
    }

public:
    int result;
    int code; // 0，可信，否则!0具体是几，表明对应的错误原因
};